﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using MessageServer.pool;
using System.Reflection;
using System.Collections;

namespace MessageServer.Handlers.hinternal
{
    /**
     * This class is used to store listener objects in a strict pool. This acts as a 
     * wrapper for the listener object. It derives from the poolable object
     * 
     * */
    public class ListenerObject : IPoolableObject, IDisposable
    {
        MessageListener _listener;              //The listener object for which this class is a wrapper

        /**
         * The listener object can only be constructed by this namespace. It is constructed only
         * for this listener passed in. It cannot be constructed for a null listener.
         * */
        internal ListenerObject(MessageListener l)
        {
            if (l == null)
                throw new NullReferenceException();
            _listener = l;
        }

        //accessor for the message listener.
        public MessageListener listener { get { return _listener; } }

        /**
         * during dispose, this function calls the Dispose of the listener
         * class. The Dispose is the last lifecycle function for the listener
         * once called, the listener object cannot be used.
         * */
        public override void Dispose()
        {
            _listener.Dispose();
            base.Dispose();
        }
    }

    /**
     * Creator class for the Listener Pool object. This class takes the type of
     * listener that has to be created and creates a listener with a default 
     * constructor. 
     * */
    public class ListenerCreator : IPoolableObjectCreator
    {
        Type _listenerType;             //The type of the listener class that needs to be pooled.

        //can be used only within this namespace and is used to create
        //objects of the given listener type.
        internal ListenerCreator(Type lt)
        {
            _listenerType = lt;
        }

        /**
         * Create a new listener object and the wrapper for it. This function assumes that the
         * listener type this creator was initialized with has a default constructor. It calls the
         * default constructor and creates a new wrapper for the listener.
         * */
        public IPoolableObject create()
        {
            ConstructorInfo c = _listenerType.GetConstructor(new Type[0]);
            MessageListener l = (MessageListener)c.Invoke(new object[0]);
            ListenerObject obj = new ListenerObject(l);
            return obj;
        }
    }

    /**
     * This is a derived listener pool from a strict object pool class. This class overrides the
     * get and release functions to call the lifecycle functions. 
     * */
	public class ListenerPool : StrictObjectPool
	{
        /** 
         * This is the default constructor for the listener pool. This is constructed for
         * the given listener type. It calls the base constructor with the listenercreator
         * for the given listener type. 
         * */
        public ListenerPool(Type listener, int wait, int min, int max) : base(new ListenerCreator(listener), wait, min, max)
        {
        }

        /**
         * Overrides the StrictObjectPool get function to call the lifecycle function
         * activated before returning the object to the caller.
         * */
        public override PoolObject get()
        {
            PoolObject obj = base.get();
            if (obj != null)
            {
                //call the lifecycle function
                ListenerObject l = obj.poolobject as ListenerObject;
                l.listener.activated();
            }
            return obj;
        }

        /**
         * Overrides the StrictObjectPool release function to call the lifecycle function
         * to call the deactivated function before returning the object to the pool.
         * */
        public override void release(PoolObject obj)
        {
            if (obj != null)
            {
                //call lifecycle functions 
                ListenerObject l = obj.poolobject as ListenerObject;
                l.listener.passivated();
            }
            base.release(obj);
        }
	}

    /**
     * The listener container class acts as a container for all the pools that are maintained
     * in the executable. This is a singleton class that creates and stores the pool for each of the
     * types registered.
     * */
    public class ListenerContainer
    {
        //singleton, which maintains the listener pools
        static ListenerContainer CONTAINER = new ListenerContainer();

        //accessor function to the singleton instance of the container
        public static ListenerContainer container { get { return CONTAINER; } }

        object _lckpool = new object();
        Hashtable _managedPools = new Hashtable();              //stores the managed pools

        /**
         * default constructor with no managed pools.
         * */
        internal ListenerContainer()
        {
        }

        /**
         * Returns true if it is managing currently the given type, else it
         * returns false.
         * */
        public bool isManaging(Type listener)
        {
            bool ret = false;
            lock (_lckpool)
            {
                ret = (_managedPools.ContainsKey(listener));
            }
            return ret;
        }

        /**
         * Adds a pool for the given type of listener and stores it in the
         * managedPools table if it is not already managed.
         * */
        public void addPool(Type listener, int wait, int min, int max)
        {
            lock (_lckpool)
            {
                if (!_managedPools.ContainsKey(listener))
                {
                    ListenerPool p = new ListenerPool(listener, wait, min, max);
                    _managedPools.Add(listener, p);
                }
            }
        }

        /**
         * returns the pool object for the given type of listener.
         * */
        public ListenerPool getPool(Type l)
        {
            ListenerPool _pool = null;

            lock (_lckpool)
            {
                if (_managedPools.ContainsKey(l))
                    _pool = (ListenerPool)_managedPools[l];
            }

            if (_pool == null)
                throw new Exception("Pool not managed by container");

            return _pool;
        }
    }
}
